home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / utils / graphic / viewers / general / amiga / he / he.c next >
Encoding:
C/C++ Source or Header  |  1991-02-24  |  19.3 KB  |  643 lines

  1. /*
  2.     HE        (great name, huh?)
  3.     
  4.         This is a simple little IFF picture viewer with support for 
  5.     pictures larger than the screen.  So what?  Well, it also handles
  6.     HAM-E pictures.  No big deal, since they're just hi-res pics, right?
  7.         Well, sort-of.  They are indeed IFF pictures, and can be shown
  8.     with any picture viewer, but there is a problem.  The HAM-E is 
  9.     triggered by the "magic cookie", which is contained in the first few
  10.     lines of the picture.  So, if you scroll the picture around, the
  11.     magic cookie gets moved offscreen, and the HAM-E unlocks.  Not cool.
  12.         Enter this viewer.  It can view just about any IFF picture you 
  13.     can throw at it.  And if it detects a HAM-E picture, it will grab the
  14.     cookie and keep it visible at all times while you scroll around.
  15.     Pretty simple, really.
  16.         If you're running under WorkBench 2.0x, the pictures will be
  17.     displayed in overscan when necessary.  This is so trivial to do under 
  18.     2.0x that I figured I might as well.  It's a lot more work under 1.3,
  19.     so I didn't bother.  You have to understand that this whole program
  20.     was done on a "whim", and I only allowed it to take a couple of hours
  21.     of my time...
  22.         I have included the source just so that struggling programmers
  23.     can use it as an example.  
  24.         Future features?  I'd like to see color cycling support, and 
  25.     maybe anim support, but I just don't have the time.  Later, maybe...
  26.         As far as the legal issues go...   Anyone who wants to use this
  27.     code in a non-commercial product is free to do so.  I do request a copy
  28.     of such a product, though.  Commercial uses are not permitted without
  29.     contacting me first (I will almost certainly grant permission, I just
  30.     want to know about things beforehand.)  You may distribute this program
  31.     as long as the source code is included, but may not make any profit
  32.     from it other than the cost of the media it is on.
  33.         HE works from the CLI only (sorry...) and is childishly simple
  34.     to operate.  Just say "HE [-n] <filename>".  Once up and running, you
  35.     click and drag the left mouse button to scroll around, and the right 
  36.     button to quit.  Pretty simple, eh?
  37.         The [-n] option will disable overscan under 2.0.  For some reason,
  38.     I have yet to be able to set my overscan preferences such that the 
  39.     HAM-E will lock on a severely overscanned image under 2.0.  This 
  40.     provides a simple, if inelegant, way to get around that.          
  41.         I do not request any donation for the use of this program (other
  42.     than for use of the source, as noted above).  But if you want to 
  43.     contact me for any reason, send your comments, flames, and hard drives
  44.     of outrageous capacity to:
  45.     
  46.             Robert Kesterson
  47.             6418 30th Street
  48.             Lubbock, TX 79407
  49.             (806)-792-3639
  50.             BIX: rkesterson
  51. */
  52.  
  53.  
  54.  
  55. #include <stdio.h>
  56. #include <ctype.h>
  57. #include <string.h>
  58. #include <exec/types.h>
  59. #include <exec/ports.h>
  60. #include <exec/memory.h>
  61. #include <intuition/intuition.h>
  62. #include <intuition/screens.h>
  63. #include <graphics/gfxmacros.h>
  64. #include <graphics/gfx.h>
  65. #include <workbench/startup.h>
  66. #include "iff.h"
  67.  
  68.                                
  69. BYTE REG_COOKIE[] = { 0xA2, 0xF5, 0x84, 0xDC, 0x6D, 0xB0, 0x7F, 0x14 };
  70. BYTE HAM_COOKIE[] = { 0xA2, 0xF5, 0x84, 0xDC, 0x6D, 0xB0, 0x7F, 0x18 };
  71.                                              
  72.                                              
  73. BOOL WB = FALSE;    /* set this to true if run from workbench            */
  74.                     /* then this silly macro will suppress printf()'s    */       
  75. #define wbprintf(x)        if(!WB)        printf(x)
  76.      
  77. BOOL NO_OVERSCAN = FALSE;
  78. BOOL WB20x = FALSE;    /* this is set true for WB 2.0x to allow overscan    */
  79.  
  80. char iffname[80];            /* iff filename                             */
  81.                                                                     
  82. UWORD colortable[64];        /* save color map for later...                   */
  83. SHORT colorcount = 0;        /* and the color count...                       */
  84.  
  85. FILE *ifffile = NULL;        /* This is the input picture                   */
  86.  
  87. BitMapHeader header;        /* This will hold the bitmap info...          */
  88.  
  89. struct Screen *screen = NULL;    /* The screen for the picture             */
  90. struct Window *window = NULL;    /* and the window to hold it              */
  91. struct BitMap *sbmap  = NULL;    /* and the actual bitmap                 */
  92. struct Window *cookie = NULL;    /* this will hold the cookie, if any    */ 
  93. struct RastPort *rport;
  94.  
  95.  
  96. struct GfxBase *GfxBase = NULL;     /* library stuff                       */
  97. struct IntuitionBase *IntuitionBase = NULL;
  98. struct LayersBase *LayersBase = NULL;
  99.  
  100. BOOL OpenStuff(void);               /* some prototypes                     */
  101. BOOL OpenLibs(void);
  102. void CheckForCookies(void);
  103. void SetOverScan(struct NewScreen *ns,BitMapHeader *bmhd);
  104. void ShowIt(void);
  105. void CloseStuff(void);
  106. struct BitMap *create_bitmap(UWORD width, UWORD height, UBYTE depth);
  107. void close_bitmap(struct BitMap *bitmap);
  108.  
  109.  
  110. /*
  111.     Here's the main function. Doesn't seem to do a whole lot, does it?
  112. */
  113.  
  114. void main(argc,argv)
  115. int argc;
  116. char **argv;
  117. {
  118.     BOOL trouble = FALSE;
  119.                   
  120.     if((argc==1) || (argv[1][0] == '?'))
  121.         {
  122.             printf("\n%s -- by Robert Kesterson",argv[0]);
  123.             printf("\nThis YAIFFV (Yet Another IFF Viewer) allows scrolling");
  124.             printf("\naround in oversize pictures, including HAM-E pictures.");
  125.             printf("\nUsage is:  %s iff_file.\n",argv[0]);
  126.             exit(10);
  127.         }
  128.     if(argv[1][0] == '-')
  129.         {
  130.             strcpy(iffname,argv[2]);
  131.             NO_OVERSCAN = TRUE;
  132.         }
  133.     else
  134.         strcpy(iffname,argv[1]);    
  135.     trouble = OpenStuff();
  136.     if(!trouble)
  137.         ShowIt();
  138.     CloseStuff();
  139. }
  140.  
  141. /*
  142.     OpenStuff() opens everything up and sets up the screen and such.
  143.     It figures out what the bitmap needs are and allocates one.
  144.     Then it sets the colormap for the screen and reads the picture into
  145.     the SuperBitMap.  Then it does some Layers fiddling to refresh the
  146.     initial window, and returns to the caller.
  147. */
  148.  
  149. BOOL OpenStuff()
  150. {
  151.     struct NewScreen newscreen;
  152.     struct NewWindow newwindow =
  153.         {
  154.             0,0,0,0,        /* left, top, width, height (fill in below) */
  155.             -1,-1,            /* use default pens                         */
  156.             MOUSEMOVE|MOUSEBUTTONS,        /* IDCMP flags                     */
  157.             BACKDROP|RMBTRAP|SUPER_BITMAP|BORDERLESS|ACTIVATE|GIMMEZEROZERO|REPORTMOUSE,
  158.             NULL,            /* no gadgets                                 */
  159.             NULL,            /* no checkmark                             */
  160.             NULL,            /* no title                                    */
  161.             NULL,            /* screen -- fill in below                     */
  162.             NULL,            /* not superbitmap  ...yet...                  */
  163.             0,0,0,0,        /* max and min sizes                         */
  164.             CUSTOMSCREEN
  165.         };
  166.     BOOL error;
  167.     SHORT count,tempheight=0, tempwidth=0;
  168.     BYTE hires=1, lace=1;
  169.  
  170.     for(count=0;count<64;count++)
  171.         colortable[count] = 0x0000;        /* initialize color table */
  172.     error = OpenLibs();
  173.     if(error)
  174.         return TRUE;
  175.     if((ifffile = fopen(iffname,"rb")) == NULL)
  176.         {                    /* hey dude, get the name right... */
  177.             wbprintf("\nCan't open IFF file!!\n");
  178.             return TRUE;
  179.         }                    /* Open the IFF file and set up the screen */
  180.     error = GetBMHD(ifffile,&header);
  181.     if(error)
  182.         {
  183.             wbprintf("\nFile error or invalid IFF file.\n");
  184.             return TRUE;
  185.         }
  186.     newscreen.LeftEdge = header.x;        /* figure out what the screen */
  187.     newscreen.TopEdge = header.y;        /* needs to look like */
  188.     newscreen.ViewModes = 0;
  189.     newscreen.Type = CUSTOMSCREEN | SCREENBEHIND | SCREENQUIET;
  190.     newscreen.Height = header.h;
  191.     newscreen.Width = header.w;
  192.     if(header.h < header.pageHeight)            /* is it a brush? */
  193.         newscreen.Height = (header.pageHeight > 240) ? 400 : 200;
  194.     else if(header.h > header.pageHeight)
  195.         newscreen.Height = header.pageHeight;    /* or a superbitmap? */
  196.     if(header.w < header.pageWidth)
  197.         newscreen.Width = (header.pageWidth > 384) ? 640 : 320;
  198.     else if(header.w > header.pageWidth)
  199.         newscreen.Width = header.pageWidth;
  200.     newscreen.Depth = header.nplanes;
  201.     newscreen.DetailPen = 0;
  202.     newscreen.BlockPen = 1;
  203.     newscreen.DefaultTitle = NULL;
  204.     newscreen.Gadgets = NULL;
  205.     newscreen.Font = NULL;                /* probably should declare one... */
  206.     newscreen.CustomBitMap = NULL;
  207.     error = GetViewModes(&newscreen, ifffile);
  208.     if(error)
  209.         {
  210.             wbprintf("\nProblem with viewmodes!\n");
  211.             return TRUE;
  212.         }
  213.     if((newscreen.Width > 384) && (newscreen.Depth <= 4) && !(newscreen.ViewModes & HAM))        
  214.         {                                    
  215.             newscreen.ViewModes |= HIRES;    
  216.             hires = 2;                        
  217.         }                                    
  218.     if(newscreen.Height > 200)            
  219.         {
  220.             newscreen.ViewModes |= LACE;    
  221.             lace = 2;
  222.         }
  223.     SetOverScan(&newscreen,&header);        
  224.     if((newscreen.Width > 384) && (newscreen.Depth <= 4) && !(newscreen.ViewModes & HAM))
  225.         newscreen.ViewModes |= HIRES;    
  226.     if(newscreen.Height > 200)                /* these might need to be   */
  227.         newscreen.ViewModes |= LACE;        /* changed, so just make sure */
  228.     if(newscreen.Width<320)
  229.         {
  230.             tempwidth = newscreen.Width;
  231.             newscreen.Width = 320;
  232.         }
  233.     if(newscreen.Height<200*lace)
  234.         {
  235.             tempheight = newscreen.Height;
  236.             newscreen.Height = 200*lace;
  237.         }
  238.     screen = (struct Screen *)OpenScreen(&newscreen);
  239.     if(!screen)
  240.         {                                    /* low on RAM, maybe? */
  241.             wbprintf("\nCan't open the screen!\n");
  242.             return TRUE;
  243.         }              
  244.     if((tempwidth) && (tempwidth < newscreen.Width))
  245.         newwindow.Width = tempwidth;
  246.     else
  247.         newwindow.Width = newscreen.Width;
  248.     if((tempheight) && (tempheight < newscreen.Height))
  249.         newwindow.Height = tempheight;
  250.     else
  251.         newwindow.Height = newscreen.Height;    /* make a screen-sized window */
  252.     newwindow.Screen = screen;
  253.     sbmap = create_bitmap(header.w,header.h,header.nplanes);
  254.     if(!sbmap)
  255.         {
  256.             wbprintf("\nNo Memory for SuperBitMap!!\n");
  257.             return TRUE;
  258.         }
  259.     newwindow.BitMap = sbmap;                /* jam bitmap into the window */
  260.     window = (struct Window *)OpenWindow(&newwindow);
  261.     if(!window)
  262.         {
  263.             wbprintf("\nCan't open a window!!\n");
  264.             return TRUE;
  265.         }
  266.     rport = window->RPort;                        /* need this later */
  267.     colorcount = GetColorMap(ifffile,colortable);   /* fix the colors  */
  268.     LoadRGB4(&screen->ViewPort,colortable,colorcount);
  269.     error = ReadPic(sbmap,ifffile,&header);         /* read the image  */
  270.     if(error)
  271.         {
  272.             wbprintf("\nError decoding IFF file!\n");
  273.             return TRUE;
  274.         }
  275.     LockLayerRom(window->WLayer);           /* refresh the window         */
  276.     CopySBitMap(window->WLayer);            /* (only do it this way the */
  277.     UnlockLayerRom(window->WLayer);         /* first time.)             */
  278.     CheckForCookies();                        /* HAM-E, by any chance?    */
  279.     ShowTitle(screen,FALSE);
  280.     ScreenToFront(screen);                  
  281.     return FALSE;
  282. }
  283.  
  284.  
  285. /*
  286.     OpenLibs() just opens the libraries we'll need and sets the WB20x
  287.     flag if we're running under 2.0x.
  288. */
  289.  
  290. BOOL OpenLibs(void)
  291. {
  292.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",36);
  293.     if(IntuitionBase)
  294.         WB20x = TRUE;
  295.     else
  296.         IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  297.     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
  298.     LayersBase = (struct Library *)OpenLibrary("layers.library",0);
  299.     if((!IntuitionBase) || (!GfxBase) || (!LayersBase))
  300.         return TRUE;        /*  Like maybe you yanked your ROMs out?  */
  301.     else
  302.         return FALSE;
  303. }
  304.  
  305.  
  306. /*
  307.     SetOverScan() just tries to intelligently set up overscan images
  308.     under workbench 2.0x.  Pretty trivial, actually.
  309. */
  310.  
  311. void SetOverScan(newscreen,header)
  312. struct NewScreen *newscreen;         
  313. BitMapHeader *header;
  314. {
  315.     SHORT hires = 1, lace = 1;
  316.     
  317.     if((newscreen->Width > 384) && (newscreen->Depth <= 4) && !(newscreen->ViewModes & HAM))        
  318.         {                                    
  319.             newscreen->ViewModes |= HIRES;    
  320.             hires = 2;                        
  321.         }                                    
  322.     if(newscreen->Height > 200)            
  323.         {
  324.             newscreen->ViewModes |= LACE;    
  325.             lace = 2;
  326.         }
  327.     if((!WB20x) || NO_OVERSCAN)        /* don't mess with overscan under 1.3 */
  328.         {
  329.             if(newscreen->Height > (200 * lace))
  330.                 newscreen->Height = 200 * lace;
  331.             if(newscreen->Width > (320 * hires))
  332.                 newscreen->Width = 320 * hires;
  333.             return;
  334.         }
  335.     if(header->h > 220 * lace)
  336.         {            
  337.             newscreen->Height = 240 * lace;     /* center if overscan */
  338.             newscreen->TopEdge -= (newscreen->Height - (200 * lace)) / 2;
  339.         }
  340.     else if(header->h > 200 * lace)
  341.         {
  342.             newscreen->Height = 220 * lace;
  343.             newscreen->TopEdge -= (newscreen->Height - (200 * lace)) / 2;
  344.         }
  345.     if(header->w > 352 * hires)                /* severe overscan? */
  346.         {
  347.             newscreen->Width = 384 * hires;     /* center it */
  348.             newscreen->LeftEdge -= (newscreen->Width - (320 * hires)) / 2;
  349.         }        
  350.     else if(header->w > 320 * hires)            /* normal overscan? */
  351.         {
  352.             newscreen->Width = 352 * hires;    /* center it */
  353.             newscreen->LeftEdge -= (newscreen->Width - (320 * hires)) / 2;
  354.         }                    
  355.     return;
  356. }
  357.  
  358. /*
  359.     CloseStuff() attempts to figure out all the garbage I didn't already
  360.     close somewhere and clean up after me.    Important when closing things
  361.     elsewhere to set them to NULL so they don't get re-closed here.  Good
  362.     way to get a lesson in meditation....
  363. */
  364.  
  365. void CloseStuff()
  366. {
  367.     if(ifffile)
  368.         fclose(ifffile);
  369.     if(cookie)
  370.         CloseWindow(cookie);
  371.     if(window)
  372.         CloseWindow(window);
  373.     if(screen)
  374.         CloseScreen(screen);
  375.     if(sbmap)
  376.         close_bitmap(sbmap);
  377.     if(LayersBase)
  378.         CloseLibrary(LayersBase);
  379.     if(GfxBase)
  380.         CloseLibrary(GfxBase);
  381.     if(IntuitionBase)
  382.         CloseLibrary(IntuitionBase);
  383. }
  384.  
  385.  
  386. /*
  387.     CheckForCookies() checks the main window's bitmap for HAM-E cookies,
  388.     assuming that they will exist only in the upper left corner of the
  389.     image (although I suppose you could put them on any scanline...).
  390.     If any are present, we set up a window _just_ big enough to hold the 
  391.     cookie lines and copy the cookie into it.  Then when you scroll the
  392.     main window around, the little cookie window will keep the HAM-E
  393.     locked in.  Simple, eh?
  394. */
  395.  
  396. void CheckForCookies()
  397. {
  398.     struct NewWindow newwindow =
  399.         {
  400.             0,0,0,0,        /* left, top, width, height (fill in below) */
  401.             -1,-1,            /* use default pens                         */
  402.             NULL,            /* IDCMP flags (none for this window)         */
  403.             BORDERLESS|GIMMEZEROZERO,
  404.             NULL,            /* no gadgets                                 */
  405.             NULL,            /* no checkmark                             */
  406.             NULL,            /* no title                                    */
  407.             NULL,            /* screen -- fill in below                     */
  408.             NULL,            /* not superbitmap                             */
  409.             0,0,0,0,        /* max and min sizes                         */
  410.             CUSTOMSCREEN
  411.         };
  412.     SHORT line,byte;
  413.     BYTE cookielines[8][8];        /* 8 lines of 8 BYTEs each for cookies    */
  414.     
  415.     for(line=0;line<8;line++)
  416.         for(byte=0;byte<8;byte++)
  417.                {
  418.                    cookielines[line][byte] = (BYTE)(ReadPixel(window->RPort,byte*2,line) << 4);
  419.                    cookielines[line][byte] |= (BYTE)ReadPixel(window->RPort,byte*2+1,line);
  420.             }
  421.     for(line=0;line<8;line++)
  422.         {
  423.             for(byte=0;byte<8;byte++)
  424.                 {
  425.                     if(cookielines[line][byte] == REG_COOKIE[byte])
  426.                         continue;
  427.                     else if(cookielines[line][byte] != HAM_COOKIE[byte])
  428.                         break;
  429.                 }
  430.             if(cookielines[line][byte] == REG_COOKIE[byte])
  431.                 continue;        /* check to see if we broke from the first loop */
  432.             else if(cookielines[line][byte] != HAM_COOKIE[byte])
  433.                 break;
  434.         }
  435.     if((line==0) && (byte<8))    /* no cookies here...    */
  436.         return;
  437.     if(line>=0)
  438.         {   
  439.             newwindow.LeftEdge = window->LeftEdge;
  440.             newwindow.TopEdge = window->TopEdge;
  441.             newwindow.Height = line+1;    /* got to be at least one...    */
  442.             newwindow.Width = 640;        /* all we'd need for now, right? */
  443.             newwindow.Screen = screen;    /* got to put it on a screen...    */
  444.             cookie = (struct Window *)OpenWindow(&newwindow);
  445.             if(!cookie)
  446.                 {
  447.                     wbprintf("Can't open Cookie window!\n");
  448.                     return;
  449.                 }
  450.             BltBitMap(sbmap,0,0,cookie->RPort->BitMap,0,0,
  451.                         cookie->Width,cookie->Height,0x0C0,0x0FF);
  452.         }
  453.     return;
  454. }
  455.  
  456.  
  457. /*
  458.     pointer data (see GetClip(), below).
  459. */
  460.  
  461. UWORD chip hand_data[] =
  462.     {
  463.         0x0000,0x0000,        /* control words */
  464.         0x0000,0x0340,        /* data words     */
  465.         0x0340,0x0CB0,
  466.         0x0550,0x0AA8,
  467.         0x0558,0x0AA4,
  468.         0x02A8,0x0554,
  469.         0x02F8,0x6504,
  470.         0x61F8,0x9204,
  471.         0x73F8,0x8C04,
  472.         0x3FF8,0x4004,
  473.         0x1FF8,0x2004,
  474.         0x1FF0,0x2008,
  475.         0x07F0,0x1808,
  476.         0x01E0,0x0610,
  477.         0x00E0,0x0110,
  478.         0x00C0,0x0100,
  479.         0x0000,0x0000        /* more control words */
  480.     };
  481.  
  482.  
  483.  
  484. void ShowIt()
  485. {
  486.     struct IntuiMessage *msg = NULL;
  487.     struct IntuiMessage tempmsg;
  488.     BOOL mousedown = FALSE;         /* TRUE if left mouse down */
  489.     BOOL message_ready = FALSE;        /* TRUE if tempmsg has a valid message */
  490.     SHORT x,y;
  491.     SHORT dx,dy;
  492.     SHORT oldx,oldy;
  493.                                         /* clear the port first thing */
  494.     while(msg = (struct IntuiMessage *)GetMsg(window->UserPort))
  495.         ReplyMsg(msg);
  496.     oldx = oldy = x = y = 0;
  497.     do
  498.         {
  499.             oldx = x;
  500.             oldy = y;
  501.             if(!message_ready)
  502.                 {
  503.                     WaitPort(window->UserPort);             /* call me sometime */
  504.                     msg = (struct IntuiMessage *)GetMsg(window->UserPort);
  505.                     memcpy(&tempmsg,msg,(unsigned int)sizeof(struct IntuiMessage));
  506.                     ReplyMsg(msg);                          /* send it back */
  507.                 }
  508.             else
  509.                 message_ready = FALSE;    /* fixin' to use tempmsg */
  510.             x = tempmsg.MouseX;            /* where's the mouse? */
  511.             y = tempmsg.MouseY;
  512.             if(tempmsg.Class == MOUSEMOVE)  /* got a mouse in motion */
  513.                 {
  514.                     if(mousedown)             /* got a button down     */
  515.                         {
  516.                             while(msg = (struct IntuiMessage *)GetMsg(window->UserPort))
  517.                                 {                /* look ahead while moving */
  518.                                     if(msg->Class == MOUSEMOVE)
  519.                                         {
  520.                                             x = msg->MouseX;
  521.                                             y = msg->MouseY;
  522.                                             ReplyMsg(msg);
  523.                                             continue;
  524.                                         }
  525.                                     else        /* not moving anymore */
  526.                                         {
  527.                                             memcpy(&tempmsg,msg,(unsigned int)sizeof(struct IntuiMessage));
  528.                                             ReplyMsg(msg);
  529.                                             message_ready = TRUE;
  530.                                             break;
  531.                                         }
  532.                                 }
  533.                         }
  534.                     if(mousedown)    /* scrolling, are we? */
  535.                         {
  536.                             dx = (oldx - x);        /* get offsets */
  537.                             dy = (oldy - y);
  538. /* bounds checks */            if(window->WLayer->Scroll_X + dx <0)
  539.                                 dx = window->WLayer->Scroll_X;
  540.                             if(window->WLayer->Scroll_Y + dy <0)
  541.                                 dy = window->WLayer->Scroll_Y;
  542.                             if(window->WLayer->Scroll_X +dx > (window->WLayer->SuperBitMap->BytesPerRow * 8-window->Width))
  543.                                 dx = window->WLayer->SuperBitMap->BytesPerRow * 8-window->Width-window->WLayer->Scroll_X;
  544.                             if(window->WLayer->Scroll_Y + dy > window->WLayer->SuperBitMap->Rows-window->Height)
  545.                                 dy = window->WLayer->SuperBitMap->Rows-window->Height-window->WLayer->Scroll_Y;
  546.                             if(window->WLayer->SuperBitMap->BytesPerRow*8 <= window->Width)
  547.                                 dx = 0;
  548.                             if(window->WLayer->SuperBitMap->Rows <= window->Height)
  549.                                 dy = 0;
  550.                             if(dx%2)     /* limit to two-pixel move increments */
  551.                                 dx--;
  552. /* Scroll BitMap */            ScrollLayer(window->WLayer->LayerInfo,window->WLayer,dx,dy);
  553.                             continue;
  554.                         }
  555.                 }
  556.             if(tempmsg.Class == MOUSEBUTTONS)
  557.                 {
  558.                     if((mousedown) && (tempmsg.Code == SELECTUP))
  559.                         {
  560.                             mousedown = FALSE;
  561.                             ClearPointer(window);
  562.                         }
  563.                     if(!mousedown)
  564.                         {
  565.                                if(tempmsg.Code == SELECTDOWN)
  566.                                 {
  567.                                     mousedown = TRUE;
  568.                                     SetPointer(window,&hand_data,15,14,0,0);
  569.                                 }
  570.                         }
  571.                     if(tempmsg.Code == MENUUP)
  572.                         break;
  573.                 }
  574.         }
  575.     while(TRUE);
  576. }
  577.  
  578. /*
  579.     Create_bitmap() is a pretty generic routine to allocate and initialize
  580.     a bitmap.
  581. */
  582.  
  583. struct BitMap *create_bitmap(width,height,depth)
  584. UWORD width,height;
  585. UBYTE depth;
  586. {
  587.     short i, error_flag = (SHORT)FALSE;
  588.     struct BitMap *pbitmap = NULL;
  589.     unsigned char *planepointer;
  590.  
  591.     if((depth>0L) && (width>0L) && (height>0L))
  592.         {
  593.             pbitmap = (struct BitMap *)AllocMem(sizeof(struct BitMap),
  594.                         MEMF_CHIP | MEMF_CLEAR);
  595.             if(pbitmap != NULL)
  596.                 {
  597.                     InitBitMap(pbitmap,depth,width,height);
  598.                     for(i=0;i<depth;i++)
  599.                         {
  600.                             planepointer = (PLANEPTR)AllocMem(RASSIZE(width,height),MEMF_CHIP|MEMF_CLEAR);
  601.                             if(planepointer)
  602.                                 pbitmap->Planes[i] = planepointer;
  603.                             else
  604.                                 error_flag = TRUE;
  605.                         }
  606.                 }
  607.         }
  608.     if(error_flag == TRUE)
  609.         {
  610.             close_bitmap(pbitmap);
  611.             pbitmap = NULL;
  612.         }
  613.     return(pbitmap);
  614. }
  615.  
  616. /*
  617.     close_bitmap() just frees up all the memory in a BitMap that was
  618.     previously allocated with create_bitmap().
  619. */
  620.  
  621. void close_bitmap(pbitmap)
  622. struct BitMap *pbitmap;
  623. {
  624.     unsigned char *planepointer;
  625.     unsigned long depth,width,height;
  626.     short i;
  627.  
  628.     if(pbitmap != NULL)
  629.         {
  630.             depth = pbitmap->Depth;
  631.             width = pbitmap->BytesPerRow * 8;
  632.             height = pbitmap->Rows;
  633.             for ( i=0; i<depth; i++)
  634.                 {
  635.                     planepointer = pbitmap->Planes[i];
  636.                     if(planepointer != NULL)
  637.                         FreeMem(planepointer,RASSIZE(width,height));
  638.                     }
  639.             FreeMem(pbitmap,sizeof(struct BitMap));
  640.         }
  641. }
  642.  
  643.